home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / Kubuntu 8.10 / kubuntu-8.10-desktop-i386.iso / casper / filesystem.squashfs / usr / sbin / cups-genppdupdate < prev    next >
Text File  |  2008-10-06  |  25KB  |  843 lines

  1. #! /usr/bin/perl -w
  2. # $Id: cups-genppdupdate.in,v 1.53 2008/09/22 11:04:24 rlk Exp $
  3. # Update CUPS PPDs for Gutenprint queues.
  4. # Copyright (C) 2002-2003 Roger Leigh (rleigh@debian.org)
  5. #
  6. # This program is free software; you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation; either version 2, or (at your option)
  9. # any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with this program; if not, write to the Free Software
  18. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19.  
  20. use strict;
  21. use Getopt::Std;
  22. use Fcntl qw(:mode);
  23.  
  24. sub parse_options ();
  25. sub update_ppd ($); # Original PPD filename
  26. sub get_ppd_fh ($$$$$); # Return contents of desired PPD
  27. sub find_ppd ($$$$); # Gutenprint Filename, driver, language (e.g. en, sv),
  28.              # region (e.g. GB, DE)
  29. sub get_ppd_data (*$$$$$); # Source PPD FH
  30.  
  31. our $opt_d; # Debug mode
  32. our $opt_h; # Help
  33. our $opt_n; # No action
  34. our $opt_q; # Quiet mode
  35. our $opt_s; # Source PPD location
  36. our $opt_p; # New PPD location
  37. our $opt_P; # PPD generator location
  38. our $opt_v; # Verbose mode
  39. our $opt_N; # Don't update PPD file options
  40. our $opt_o; # Output directory
  41. our $opt_r; # Gutenprint version
  42. our $opt_i; # Interactive
  43. our $opt_f; # Force upgrade
  44. our $opt_l; # Language
  45.  
  46. my $debug = 0;
  47. my $verbose = 0;   # Verbose output
  48. my $interactive = 0;
  49. my $quiet = 0;     # No output
  50. my $no_action = 0; # Don't output files
  51. my $reset_defaults = 0;        # Reset options to default settings
  52. my $version = "5.2";
  53. my $micro_version = "5.2.0-rc1";
  54. my $use_static_ppd = "no";
  55. my $file_version = '"5.2.0-rc1"$';
  56.  
  57. my $ppd_dir = "/etc/cups/ppd"; # Location of in-use CUPS PPDs
  58. my $ppd_root_dir = "/usr/share/ppd";
  59. my $ppd_base_dir = "$ppd_root_dir/gutenprint/$version"; # Available PPDs
  60. my $ppd_out_dir = "";        # By default output into source directory
  61. my $gzext = ".gz";
  62. my $updated_ppd_count = 0;
  63. my $skipped_ppd_count = 0;
  64. my $failed_ppd_count = 0;
  65. my $exit_after_parse_args = 0;
  66. my @languages = qw(Global C cs da de el en_GB es fr hu ja nb nl pl pt sk sv zh_TW);
  67.  
  68. my $serverdir = "/usr/lib/cups";
  69. my $driver_bin = "$serverdir/driver/gutenprint.$version";
  70. my $driver_version = "";
  71. if (-x $driver_bin) {
  72.     $driver_version = `$driver_bin VERSION`;
  73.     chomp $driver_version;
  74. }
  75.  
  76. $Getopt::Std::STANDARD_HELP_VERSION = 1;
  77.  
  78. my @ppd_files; # A list of in-use Gutenprint PPD files
  79.  
  80. # Used to convert a language name to its two letter code
  81. my %languagemappings = (
  82.             "chinese"    => "cn",
  83.             "danish"     => "da",
  84.             "dutch"      => "nl",
  85.             "english"    => "en",
  86.             "finnish"    => "fi",
  87.             "french"     => "fr",
  88.             "german"     => "de",
  89.             "greek"      => "el",
  90.             "hungarian"  => "hu",
  91.             "italian"    => "it",
  92.             "japanese"   => "jp",
  93.             "norwegian"  => "no",
  94.             "polish"     => "pl",
  95.             "portuguese" => "pt",
  96.             "russian"    => "ru",
  97.             "slovak"     => "sk",
  98.             "spanish"    => "es",
  99.             "swedish"    => "sv",
  100.             "turkish"    => "tr"
  101. );
  102.  
  103.  
  104. # Check command-line options...
  105.  
  106. parse_options();
  107.  
  108.  
  109. # Set a secure umask...
  110.  
  111. umask 0177;
  112.  
  113.  
  114. # Find all in-use Gutenprint PPD files...
  115. # For case-insensitive filesystems, use only one of .ppd and .PPD
  116. # (bug 1929738).
  117.  
  118. if (@ARGV) {
  119.     my $f;
  120.     foreach $f (@ARGV) {
  121.     if (-f $f and ($f =~ /\.ppd$/i or $f =~ /\//)) {
  122.         if (-f $f) {
  123.         push @ppd_files, $f;
  124.         } else {
  125.         print STDERR "Cannot find file $f\n";
  126.         }
  127.     } elsif (-f "$ppd_dir/$f" or
  128.          -f "$ppd_dir/$f.ppd" or
  129.          -f "$ppd_dir/$f.PPD") {
  130.         if (-f "$ppd_dir/$f") {
  131.         push @ppd_files, "$ppd_dir/$f";
  132.         } elsif (-f "$ppd_dir/$f.ppd") {
  133.         push @ppd_files, "$ppd_dir/$f.ppd";
  134.         } elsif (-f "$ppd_dir/$f.PPD") {
  135.         push @ppd_files, "$ppd_dir/$f.PPD";
  136.         }
  137.     }  else {
  138.         print STDERR "Cannot find file $ppd_dir/$f, $ppd_dir/$f.ppd, or $ppd_dir/$f.PPD\n";
  139.     }
  140.     }
  141. } else {
  142.     my @ppdtmp = glob("$ppd_dir/*.{ppd,PPD}");
  143.     my (%ppd_map);
  144.     map { $ppd_map{$_} = 1 } @ppd_files;
  145.     foreach my $f (@ppdtmp) {
  146.     if ($f =~ /\.PPD$/) {
  147.         my ($g) = $f;
  148.         $g =~ s/\.PPD$/.ppd/;
  149.         if (! $ppd_map{$g}) {
  150.         push @ppd_files, $f;
  151.         }
  152.     } else {
  153.         push @ppd_files, $f;
  154.     }
  155.     }
  156. }
  157.  
  158. # Update each of the Gutenprint PPDs, where possible...
  159.  
  160. foreach (@ppd_files) {
  161.     my ($status) = update_ppd($_);
  162.     last if ($status == -2);
  163.     $failed_ppd_count++ if ($status == 0);
  164.     $updated_ppd_count++ if ($status == 1);
  165.     $skipped_ppd_count++ if ($status == -1);
  166. }
  167.  
  168. if (!$quiet || $verbose) {
  169.     if (!@ppd_files) {
  170.     print STDOUT "No Gutenprint PPD files to update.\n";
  171.     } elsif ($updated_ppd_count > 0) {
  172.     my $plural = $updated_ppd_count == 1 ? "" : "s";
  173.     print STDOUT "Updated $updated_ppd_count PPD file${plural}.";
  174.     if (!defined $opt_o || $opt_o ne "") {
  175.         print STDOUT "Restart cupsd for the changes to take effect.";
  176.     }
  177.     print STDOUT "\n";
  178.     } else {
  179.     if ($failed_ppd_count > 0) {
  180.         print STDOUT "Failed to update any PPD files\n";
  181.     } else {
  182.         print STDOUT "Did not update any PPD files\n";
  183.     }
  184.     }
  185. }
  186. exit ($failed_ppd_count > 0);
  187.  
  188. sub HELP_MESSAGE($;$$$) {
  189.     my ($fh) = @_;
  190.     print $fh "Usage: $0 [OPTION]... [PPD_FILE]...\n";
  191.     print $fh "Update CUPS+Gutenprint PPD files.\n\n";
  192.     print $fh "  -d flags    Enable debugging\n";
  193.     print $fh "  -h          Display this help text\n";
  194.     print $fh "  -n          No-action.  Don't overwrite any PPD files.\n";
  195.     print $fh "  -q          Quiet mode.  No messages except errors.\n";
  196.     print $fh "  -s ppd_dir  Use ppd_dir as the source PPD directory.\n";
  197.     print $fh "  -p ppd_dir  Update PPD files in ppd_dir.\n";
  198.     print $fh "  -P driver   Use the specified driver binary to generate PPD files.\n";
  199.     print $fh "  -v          Verbose messages.\n";
  200.     print $fh "  -N          Reset options to defaults.\n";
  201.     print $fh "  -o out_dir  Output PPD files to out_dir.\n";
  202.     print $fh "  -r version  Use PPD files for Gutenprint major.minor version.\n";
  203.     print $fh "  -f          Ignore new PPD file safety checks.\n";
  204.     print $fh "  -i          Prompt (interactively) for each PPD file.\n";
  205.     print $fh "  -l language Language choice (Gutenprint 5.1 or below).\n";
  206.     print $fh "              Choices: " . join(" ", @languages) . "\n";
  207.     print $fh "              Or -loriginal to preserve original language\n";
  208.     print $fh "                 with Gutenprint 5.2 or above\n";
  209.     exit(0);
  210. }
  211.  
  212. # Getopt::Std calls VERSION_MESSAGE followed by HELP_MESSAGE if --help
  213. # is passed.  If --version is passed, it calls only VERSION_MESSAGE.
  214. # So we have to make sure to exit, but we want to allow --help to
  215. # print out the help message.
  216. sub VERSION_MESSAGE($;$$$) {
  217.     my ($fh) = @_;
  218.     print "cups-genppdupdate from Gutenprint $micro_version\n";
  219.     $exit_after_parse_args = 1;
  220. }
  221.  
  222. sub help() {
  223.     HELP_MESSAGE(\*STDOUT);
  224. }
  225.  
  226. sub parse_options () {
  227.     if (!getopts('d:hnqs:vNo:p:P:r:ifl:')) {
  228.     help();
  229.     }
  230.     if ($opt_n) {
  231.     $no_action = 1;
  232.     }
  233.     if ($opt_d) {
  234.     $debug = $opt_d;
  235.     }
  236.     if ($opt_v) {
  237.     $verbose = 1;
  238.     $quiet = 0;
  239.     }
  240.     if ($opt_q) {
  241.     $verbose = 0;
  242.     $quiet = 1;
  243.     }
  244.     if ($opt_N) {
  245.     $reset_defaults = 1;
  246.     }
  247.     if ($opt_o) {
  248.     if (-d $opt_o) {
  249.         $ppd_out_dir = "$opt_o";
  250.     }
  251.     else {
  252.         die "$opt_o: invalid directory: $!\n";
  253.     }
  254.     }
  255.     if ($opt_r) {
  256.     if ($version ne $opt_r) {
  257.         $version = $opt_r;
  258.         if ($opt_s) {
  259.         if (-d $opt_s) {
  260.             $ppd_base_dir = "$opt_s";
  261.             $driver_bin = "";
  262.             $use_static_ppd = "yes";
  263.         } else {
  264.             die "$opt_s: invalid directory: $!\n";
  265.         }
  266.         } else {
  267.         $ppd_base_dir = "$ppd_root_dir/gutenprint/$version";
  268.         $driver_bin = "$serverdir/driver/gutenprint.$version";
  269.         }
  270.         $driver_version = "";
  271.         # If user specifies version, we're not going to be able to check
  272.         # for an exact match.
  273.         $file_version = "\"$version";
  274.         if (-x $driver_bin) {
  275.         $driver_version = `$driver_bin VERSION`;
  276.         $use_static_ppd = "no";
  277.         chomp $driver_version;
  278.         $file_version = "\"$driver_version\"\$";
  279.         } elsif (! -d $ppd_base_dir && ! -l $ppd_base_dir) {
  280.         die "Gutenprint $version does not appear to be installed!\n";
  281.         }
  282.     }
  283.     }
  284.     if ($opt_s) {
  285.     if (-d $opt_s) {
  286.         $ppd_base_dir = "$opt_s";
  287.         $driver_bin = "";
  288.         $driver_version = "";
  289.         $use_static_ppd = "yes";
  290.     }
  291.     else {
  292.         die "$opt_s: invalid directory: $!\n";
  293.     }
  294.     }
  295.     if ($opt_p) {
  296.     if (-d $opt_p) {
  297.         $ppd_dir = "$opt_p";
  298.     }
  299.     else {
  300.         die "$opt_p: invalid directory: $!\n";
  301.     }
  302.     }
  303.     if ($opt_P) {
  304.     if (-x $opt_P) {
  305.         $driver_bin = "$opt_P";
  306.         $driver_version = `$driver_bin VERSION`;
  307.         chomp $driver_version;
  308.         $use_static_ppd = "no";
  309.     }
  310.     else {
  311.         die "$opt_P: invalid executable: $!\n";
  312.     }
  313.     }
  314.     if ($opt_h) {
  315.     help();
  316.     }
  317.     if ($opt_l && lc $opt_l ne "original" && ! grep { $_ eq $opt_l } @languages) {
  318.     print STDERR "Unknown language '$opt_l'\n";
  319.     help();
  320.     }
  321.     if ($opt_i) {
  322.     $interactive = 1;
  323.     }
  324.     if ($exit_after_parse_args) {
  325.     exit(0);
  326.     }
  327.     if ($verbose && $driver_version ne "") {
  328.     print STDOUT "Updating PPD files from Gutenprint $driver_version\n";
  329.     }
  330. }
  331.  
  332. sub get_ppd_fh($$$$$) {
  333.     my ($ppd_source_filename, $filename, $driver, $locale, $region) = @_;
  334.  
  335.     my $source_data;
  336.     my ($new_ppd_filename);
  337.  
  338.     if ($use_static_ppd eq "no" && $driver_version ne "") {
  339.     my ($simplified);
  340.     if ($filename =~ m,.*/([^/]*)(.sim)(.ppd)?(.gz)?$,) {
  341.         $simplified = "simple";
  342.     } else {
  343.         $simplified = "expert";
  344.     }
  345.     my ($url);
  346.     my (@url_list);
  347.     if (((defined $opt_r && $opt_r < 5.2) ||
  348.          (defined $opt_l && $opt_l ne "")) &&
  349.         $locale ne "") {
  350.         if ($region) {
  351.         push @url_list, "gutenprint.$version://$driver/$simplified/${locale}_${region}";
  352.         }
  353.         push @url_list, "gutenprint.$version://$driver/$simplified/${locale}";
  354.     }
  355.     push @url_list, "gutenprint.$version://$driver/$simplified";
  356.     foreach $url (@url_list) {
  357.         $new_ppd_filename = $url;
  358.         if ($debug & 8) {
  359.         print "Trying $driver_bin cat $url for $driver, $simplified, $locale, $region\n";
  360.         }
  361.         if (open PPD, "$driver_bin cat $url |") {
  362.         return ($new_ppd_filename, \*PPD);
  363.         }
  364.     }
  365.     # Otherwise fall through and try to find a static PPD
  366.     }
  367.  
  368.     # Search for a PPD matching our criteria...
  369.  
  370.     $new_ppd_filename = find_ppd($filename, $driver, $locale, $region);
  371.     if (!defined($new_ppd_filename)) {
  372.         # There wasn't a valid source PPD file, so give up.
  373.         print STDERR "$ppd_source_filename: no valid candidate for replacement.  Skipping\n";
  374.         print STDERR "$ppd_source_filename: please upgrade this PPD manually\n";
  375.     return ("", undef);
  376.     }
  377.     if ($debug & 1) {
  378.     print "Candidate PPD: $new_ppd_filename\n";
  379.     }
  380.  
  381.     my $suffix = "\\" . $gzext; # Add '\', so m// matches the '.'.
  382.     if ($new_ppd_filename =~ m/.gz$/) { # Decompress input buffer
  383.     open GZIN, "gunzip -c $new_ppd_filename |"
  384.         or die "$_: can't open for decompression: $!";
  385.     return ($new_ppd_filename, \*GZIN);
  386.     } else {
  387.     open SOURCE, $new_ppd_filename
  388.         or die "$new_ppd_filename: can't open source file: $!";
  389.     binmode SOURCE;
  390.     return ($new_ppd_filename, \*SOURCE);
  391.     }
  392. }
  393.  
  394. # Update the named PPD file.
  395. sub update_ppd ($) {
  396.     my $ppd_source_filename = $_;
  397.     my $ppd_dest_filename = $ppd_source_filename;
  398.     if ($ppd_out_dir) {
  399.     $ppd_dest_filename =~ s;(.*)/([^/]+);$2;;
  400.     $ppd_dest_filename = "$ppd_out_dir/$ppd_dest_filename";
  401.     }
  402.  
  403.     open ORIG, $_ or die "$_: can't open PPD file: $!";
  404.     seek (ORIG, 0, 0) or die "can't seek to start of PPD file: $!";
  405.     my @orig_metadata = stat(ORIG);
  406.     if ($debug & 1) {
  407.     print "Source Filename: $ppd_source_filename\n";
  408.     }
  409.     my ($filename) = "";
  410.     my ($driver) = "";
  411.     my ($gutenprintdriver) = "";
  412.     my ($locale) = "";
  413.     my ($lingo) = "";
  414.     my ($region) = "";
  415.     my ($valid) = 0;
  416.     my ($orig_locale) = "";
  417.     while (<ORIG>) {
  418.     if (/\*StpLocale:/) {
  419.         ($locale) = m/^\*StpLocale:\s*\"(.*)\"$/;
  420.         $orig_locale = $locale;
  421.         $valid = 1;
  422.     } elsif (/^\*LanguageVersion/) {
  423.         ($lingo) = m/^\*LanguageVersion:\s*(.*)$/;
  424.     } elsif (/^\*StpDriverName:/ ) {
  425.         ($driver) = m/^\*StpDriverName:\s*\"(.*)\"$/;
  426.         $valid = 1;
  427.     } elsif (/\*%End of / && $driver eq "") {
  428.         ($driver) = m/^\*%End of\s*(.*).ppd$/;
  429.     } elsif (/^\*StpPPDLocation:/ ) {
  430.         ($filename) = m/^\*StpPPDLocation:\s*\"(.*)\"$/;
  431.         $valid = 1;
  432.     } elsif (/^\*%Gutenprint Filename:/) {
  433.         $valid = 1;
  434.     }
  435.     if ($filename and $driver and $lingo and $locale) {
  436.         last;
  437.     }
  438.     if (! $valid && /^\*OpenUI/) {
  439.         last;
  440.     }
  441.     }
  442.     if (! $valid) {
  443. #    print STDERR "Skipping $ppd_source_filename: not a Gutenprint PPD file\n";
  444.     return -1;
  445.     }
  446.     if (defined $opt_l && $opt_l ne "" && lc $opt_l ne "original") {
  447.     $locale = $opt_l;
  448.     $orig_locale = $locale;
  449.     }
  450.     if ($debug & 2) {
  451.     print "Gutenprint Filename: $filename\n";
  452.     if ($opt_l) {
  453.         print "Locale: $locale (from -l)\n";
  454.     } else {
  455.         print "Locale: $locale\n";
  456.     }
  457.     print "Language: $lingo\n";
  458.     print "Driver: $driver\n";
  459.     }
  460.     if ($locale) {
  461.     # Split into the language and territory.
  462.     ($locale, $region) = split(/_/, $locale);
  463.     } else {
  464.     # Split into the language and territory.
  465.     ($locale, $region) = split(/_/, $lingo);
  466.     # Convert language into language code.
  467.     $locale = $languagemappings{"\L$lingo"};
  468.     if (!defined($locale)) {
  469.         $locale = "C"; # Fallback if there isn't one.
  470.     }
  471.     }
  472.     if (! defined($region)) {
  473.     $region = "";
  474.     }
  475.     if ($debug & 2) {
  476.     print "Base Locale: $locale\n";
  477.     print "Region: $region\n";
  478.     }
  479.  
  480.     # Read in the new PPD, decompressing it if needed...
  481.  
  482.     my ($new_ppd_filename, $source_fd) =
  483.     get_ppd_fh($ppd_source_filename, $filename, $driver, $locale, $region);
  484.  
  485.     if (! defined $source_fd) {
  486.     print "Unable to retrieve PPD file!\n";
  487.     return 0;
  488.     }
  489.  
  490.     if ($interactive) {
  491.     print "Update PPD $ppd_source_filename from $new_ppd_filename [nyq]? ";
  492.     my $input = readline(*STDIN);
  493.     if ($input =~ /^q/i) {
  494.         close $source_fd;
  495.         print "Skipping all...\n";
  496.         return -2;
  497.     } elsif (! ($input =~ /^y/i)) {
  498.         close $source_fd;
  499.         print "Skipping...\n";
  500.         return -1;
  501.     }
  502.     }
  503.  
  504.     # Extract the default values from the original PPD...
  505.  
  506.     seek(ORIG, 0, 0);
  507.  
  508.     my ($odt, $oopt, $ores, $odef) = get_ppd_data(ORIG, 1, 0, 1, 1, 0);
  509.     my ($ndt, $nopt, $nres, $ndef, $source_data) = get_ppd_data($source_fd, 1, 1, 1, 1, 1);
  510.  
  511.     # Close original and temporary files...
  512.  
  513.     close ORIG;
  514.     if (! close $source_fd) {
  515.     print "Unable to retrieve new PPD file: $!\n";
  516.     return 0;
  517.     }
  518.  
  519.     my %orig_default_types = %$odt;
  520.     my %new_default_types = %$ndt;
  521.     my %defaults = %$odef;
  522.     my %new_defaults = %$ndef;
  523.     my %options = %$nopt;
  524.     my %resolution_map = %$nres;
  525.     my %old_resolution_map = reverse %$ores;
  526.  
  527.     # Store previous language in the PPD file so that -l original works
  528.     # correctly.
  529.  
  530.     if ($orig_locale ne "") {
  531.     $source_data =~ s/(\*StpLocale:\s*\")(.*)(\")/$1$orig_locale$3/;
  532.     }
  533.  
  534.     if ($debug & 4) {
  535.     print "Options (Old->New Default Type):\n";
  536.     foreach (sort keys %options) {
  537.         my ($old_type) = $orig_default_types{$_};
  538.         my ($new_type) = $new_default_types{$_};
  539.         if (! defined($old_type)) {
  540.         $old_type = '(New)';
  541.         }
  542.         if ($old_type ne $new_type) {
  543.         print "  $_ ($old_type -> $new_type) :  ";
  544.         } else {
  545.         print "  $_ ($new_type) :  ";
  546.         }
  547.         my ($def) = $defaults{"Default$_"};
  548.         foreach my $opt (@{$options{$_}}) {
  549.         if (defined $def && $def eq $opt) {
  550.             print "*";
  551.         }
  552.         print "$opt ";
  553.         }
  554.         print "\n";
  555.     }
  556.     if (keys %resolution_map) {
  557.         print "Resolution Map:\n";
  558.         foreach (sort keys %resolution_map) {
  559.         print "   $_: $resolution_map{$_}\n";
  560.         }
  561.     }
  562.     if (keys %old_resolution_map) {
  563.         print "Old Resolution Map:\n";
  564.         foreach (sort keys %old_resolution_map) {
  565.         print "   $_: $old_resolution_map{$_}\n";
  566.         }
  567.     }
  568.     print "Non-UI Defaults:\n";
  569.     foreach (sort keys %defaults) {
  570.         my ($xkey) = $_;
  571.         $xkey =~ s/^Default//;
  572.         if (! defined ($options{$xkey})) {
  573.         print "  $_: $defaults{$_}\n";
  574.         }
  575.     }
  576.     print "Default Types of dropped options:\n";
  577.     foreach (sort keys %orig_default_types) {
  578.         if (! defined($options{$_})) {
  579.         print "  $_: $orig_default_types{$_}\n";
  580.         }
  581.     }
  582.     }
  583.  
  584.     if ($no_action) {
  585.     if (!$quiet || $verbose) {
  586.         if ($ppd_dest_filename eq $ppd_source_filename) {
  587.         print STDOUT "Would update $ppd_source_filename using $new_ppd_filename\n";
  588.         } else {
  589.         print STDOUT "Would update $ppd_source_filename to $ppd_dest_filename using $new_ppd_filename\n";
  590.         }
  591.     }
  592.     return 0;
  593.     }
  594.  
  595.     if  (! $reset_defaults) {
  596.     # Update source buffer with old defaults...
  597.  
  598.     # Loop through each default in turn.
  599. default_loop:
  600.     foreach my $default_option (sort keys %defaults) {
  601.         my $option;
  602.         my $default_option_value = $defaults{$default_option};
  603.         ($option = $default_option) =~ s/Default//; # Strip off `Default'
  604.         # Check method is valid
  605.         my $orig_method = $orig_default_types{$option};
  606.         my $new_method = $new_default_types{$option};
  607.         my $new_default = $new_defaults{$default_option};
  608.         if ((!defined($orig_method) || !defined($new_method)) ||
  609.         $orig_method ne $new_method) {
  610.         next;
  611.         }
  612.         if (defined($new_default) &&
  613.         $default_option_value eq $new_default) {
  614.         if ($verbose) {
  615.             print "$ppd_source_filename: Preserve *$default_option ($default_option_value)\n";
  616.         }
  617.         next;
  618.         }
  619.         if ($new_method eq "PickOne") {
  620.         # Check the old setting is valid
  621.         foreach my $opt (@{$options{$option}}) {
  622.             my $def_option = $default_option_value;
  623.             my $odef_option = $def_option;
  624.             if ($option eq "Resolution" &&
  625.             defined $old_resolution_map{$def_option}) {
  626.             if ($debug & 4) {
  627.                 print "Intermapping old resolution $def_option to $old_resolution_map{$def_option}\n";
  628.             }
  629.             $def_option = $old_resolution_map{$def_option};
  630.             }
  631.             my @dopts = ($def_option);
  632.             if ($def_option ne $odef_option) {
  633.             push @dopts, $odef_option;
  634.             }
  635.  
  636.             foreach my $dopt (@dopts) {
  637.             if (($dopt eq $opt) ||
  638.                 ($option eq "Resolution" &&
  639.                  (defined $resolution_map{$dopt}) &&
  640.                  ($dopt = $resolution_map{$dopt}) eq $opt)) { # Valid option
  641.                 # Set the option in the new PPD
  642.                 $source_data =~ s/^\*($default_option).*/*$1:$dopt/m;
  643.                 if ($verbose) {
  644.                 print "$ppd_source_filename: Set *$default_option to $dopt\n";
  645.                 }
  646.                 next default_loop;
  647.             }
  648.             }
  649.         }
  650.         warn "Warning: $ppd_source_filename: Invalid option: *$default_option: $defaults{$default_option}.  Using default setting $new_defaults{$default_option}.\n";
  651.         next;
  652.         }
  653.         warn "Warning: $ppd_source_filename: PPD OpenUI method $new_default_types{$default_option} not understood.\n";
  654.     }
  655.     }
  656.  
  657.     # Write new PPD...
  658.  
  659.     my $tmpnew = "${ppd_dest_filename}.new";
  660.     if (! open NEWPPD, "> $tmpnew") {
  661.     warn "Can't create $tmpnew: $!\n";
  662.     return 0;
  663.     }
  664.     print NEWPPD $source_data;
  665.     if (! close NEWPPD) {
  666.     warn "Can't write to $tmpnew: $!\n";
  667.     unlink $tmpnew;
  668.     return 0;
  669.     }
  670.  
  671.     if (! rename $tmpnew, $ppd_dest_filename) {
  672.     warn "Can't rename $tmpnew to $ppd_dest_filename: $!\n";
  673.     unlink $tmpnew;
  674.     return 0;
  675.     }
  676.     chown($orig_metadata[4], $orig_metadata[5], $ppd_dest_filename);
  677.     chmod(($orig_metadata[2] & 0777), $ppd_dest_filename);
  678.  
  679.     if (!$quiet || $verbose) {
  680.     if ($ppd_dest_filename eq $ppd_source_filename) {
  681.         print STDOUT "Updated $ppd_source_filename using $new_ppd_filename\n";
  682.     } else {
  683.         print STDOUT "Updated $ppd_source_filename to $ppd_dest_filename using $new_ppd_filename\n";
  684.     }
  685.     }
  686.     return 1;
  687.     # All done!
  688. }
  689.  
  690. # Find a suitable source PPD file
  691. sub find_ppd ($$$$) {
  692.     my($gutenprintfilename, $drivername, $lang, $region) = @_;
  693.     my $file; # filename to return
  694.     my ($key) = '^\\*FileVersion:[     ]*' . "$file_version";
  695.     my ($lingo, $suffix, $base, $basedir);
  696.     my ($current_best_file, $current_best_time);
  697.     my ($stored_name, $stored_dir, $simplified);
  698.     $stored_name = $gutenprintfilename;
  699.     $stored_name =~ s,.*/([^/]+\.[0-9]+\.[0-9]+)(\.sim)?(\.ppd)?(\.gz)?$,$1,;
  700.     if ($gutenprintfilename =~ m,.*/([^/]*)(\.sim)(\.ppd)?(\.gz)?$,) {
  701.     $simplified = ".sim";
  702.     } else {
  703.     $simplified = "";
  704.     }
  705.     $stored_dir = $gutenprintfilename;
  706.     $stored_dir =~ s,(.*)/([^/]*)$,$1,;
  707.  
  708.     $current_best_file = "";
  709.     $current_best_time = 0;
  710.     my (@basedirs);
  711.     if ($opt_s) {
  712.     @basedirs = ($opt_s);
  713.     } else {
  714.     @basedirs = ($ppd_base_dir, $stored_dir, $ppd_root_dir);
  715.     }
  716.  
  717.     my (@lingos);
  718.     if ($region ne "") {
  719.     push @lingos, "${lang}_${region}/";
  720.     }
  721.     push @lingos, "$lang/";
  722.     if ($lang ne "C") {
  723.     push @lingos, "C/";
  724.     }
  725.     push @lingos, "en/", "";
  726.     push @lingos, "Global/";
  727.     my (@bases);
  728.     push @bases, "stp-${drivername}.$version${simplified}";
  729.     push @bases, "${drivername}.$version${simplified}";
  730.     if ($stored_name ne "${drivername}.$version${simplified}" and
  731.     $stored_name ne "stp-${drivername}.$version${simplified}") {
  732.     push @bases, $stored_name;
  733.     }
  734.     push @bases, $drivername;
  735.  
  736.     # All possible candidates, in order of usefulness and gzippedness
  737.     foreach $lingo (@lingos) {
  738.     foreach $suffix (".ppd$gzext",
  739.              ".ppd") {
  740.         foreach $base (@bases) {
  741.         foreach $basedir (@basedirs) {
  742.                     if ($basedir eq "" || $base eq "") { next; }
  743.             my ($fn) = "$basedir/$lingo$base$suffix";
  744.             if ($debug & 8) {
  745.                         print "Trying $fn for $gutenprintfilename, $lang, $region\n";
  746.                     }
  747. # Check that it is a regular file, owned by root.root, not writable
  748. # by other, and is readable by root.  i.e. the file is secure.
  749.             my @sb = stat $fn or next;
  750.             if ($debug & 8) {
  751.                         print "  Candidate $fn for $gutenprintfilename, $lang, $region\n";
  752.                     }
  753.             if ($opt_f || (S_ISREG($sb[2]) && ($sb[4] == 0))) {
  754.             # Check that the file is a valid Gutenprint PPD file
  755.             # of the correct version.
  756.             my $new_file_version;
  757.             if ($fn =~ m/\.gz$/) {
  758.                 $new_file_version = `gunzip -c $fn | grep '$key'`;
  759.             } else {
  760.                 $new_file_version = `cat $fn | grep '$key'`;
  761.             }
  762.             if ($new_file_version ne "") {
  763.                             if ($debug & 8) {
  764.                     print "   Format valid: time $sb[9] best $current_best_time prev $current_best_file cur $fn!\n";
  765.                 }
  766.                 if ($sb[9] > $current_best_time) {
  767.                 $current_best_time = $sb[9];
  768.                 $current_best_file = $fn;
  769.                         if ($debug & 8) {
  770.                                     print STDERR "***current_best_file is $fn\n";
  771.                                 }
  772.                 }
  773.             } elsif ($debug & 8) {
  774.                 print "   Format invalid\n";
  775.             }
  776.             }
  777.             else {
  778.             $_ = $fn;
  779.             if (! -d $fn && ! /\/$/) {
  780.                 print STDERR "$fn: not a regular file, or insecure ownership and permissions.  Skipped\n";
  781.             }
  782.             }
  783.         }
  784.         }
  785.     }
  786.     }
  787.     if ($current_best_file) {
  788.         return $current_best_file;
  789.     }
  790. # Yikes!  Cannot find a valid PPD file!
  791.     return undef;
  792. }
  793.  
  794. # Return default type, options, resolutions, and default values.
  795. # More efficient since it takes only one pass over the data.
  796. sub get_ppd_data(*$$$$$) {
  797.     my ($fh, $types, $opts, $resolutions, $defaults, $data) = @_;
  798.     my (%options, %defaults, %resolution_map, %default_types);
  799.     my $cur_opt = "";
  800.     my (@optionlist);
  801.     my ($source_data) = "";
  802.     if ($reset_defaults) {
  803.     $types = 0;
  804.     $opts = 0;
  805.     $resolutions = 0;
  806.     $defaults = 0;
  807.     }
  808.  
  809.     if ($resolutions || $types || $opts || $defaults || $data) {
  810.     while (<$fh>) {
  811.         $source_data .= $_ if ($data);
  812.         chomp;
  813.         if (($types || $opts) && m/^\*OpenUI/) {
  814.         my ($key, $value) = /^\*OpenUI\s\*([[:alnum:]]+).*:\s([[:alnum:]]+)/;
  815.         if ($key && $value) {
  816.             $default_types{$key}=$value;
  817.             $cur_opt = $key;
  818.         }
  819.         } elsif ($opts && m/^\*CloseUI/) {
  820.         if ($cur_opt ne "") {
  821.             $options{$cur_opt} = [ @optionlist ];
  822.             $cur_opt = "";
  823.         }
  824.         @optionlist = ();
  825.         } elsif ($opts && m/^\*$cur_opt/) {
  826.         my ($value) = /^\*$cur_opt\s*([[:alnum:]]+)[\/:]/;
  827.         if (defined $value && $value) {
  828.             push @optionlist, $value;
  829.         }
  830.         } elsif ($resolutions && m/^\*StpResolutionMap:/) {
  831.         my ($junk, $new, $old) = split;
  832.         $resolution_map{$old} = $new;
  833.         } elsif ($defaults && m/^\*Default/) {
  834.         my($key, $value) = /^\*([[:alnum:]]+):\s*([[:alnum:]]+)/;
  835.         if ($key && $value) {
  836.             $defaults{$key}=$value;
  837.         }
  838.         }
  839.     }
  840.     }
  841.     return (\%default_types, \%options, \%resolution_map, \%defaults, $source_data);
  842. }
  843.